/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.saber.certificacao.ejbs.stateless;

import br.com.saber.certificacao.ejbs.jms.jmsEmailUtilitarios.interfaces.EmailSendLocal;
import br.com.saber.certificacao.ejbs.stateless.interfaces.RolesBeanLocal;
import br.com.saber.certificacao.ejbs.jms.jmsEmailUtilitarios.SimpleEmail;
import br.com.saber.certificacao.ejbs.stateless.interfaces.UsuarioBeanLocal;
import br.com.saber.certificacao.enums.Papeis;
import br.com.saber.certificacao.modelos.Roles;
import br.com.saber.certificacao.modelos.Usuario;
import br.com.saber.certificacao.modelos.validadores.UsuarioValidador;
import br.com.saber.certificacao.modelos.validadores.interfaces.ValidadorInterface;
import br.com.saber.certificacao.utils.Criptografia;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.commons.lang.StringUtils;

/**
 *
 * @author gbvbahia
 */
@Stateless
public class UsuarioBean implements UsuarioBeanLocal {

    @EJB
    private EmailSendLocal emailSendBean;
    @EJB
    private RolesBeanLocal rolesBean;
    @PersistenceContext(name = "jdbc/saber")
    private EntityManager manager;

    @Override
    public void salvarUsuario(Usuario usuario, String urlFinanceiro) {
        usuario = verificaRoles(usuario);
        String newPass = null;
        if (StringUtils.isBlank(usuario.getSenha())) {
            newPass = this.geraSenha();
            usuario.setSenha(Criptografia.encodePassword(newPass, usuario.getRoles()));
        }
        ValidadorInterface<Usuario, UsuarioBeanLocal> uv = new UsuarioValidador();
        uv.validar(usuario, this, null);
        if (usuario.getId() == null) {
            manager.persist(usuario);
        } else {
            manager.merge(usuario);
        }
        manager.flush();
        if (newPass != null) {
            avisaSenhaEmail(newPass, urlFinanceiro, usuario);
            Logger.getLogger(this.getClass().getName()).log(Level.INFO, "E-mail enviado ao usuário: {0} para: {1}", new Object[]{usuario.getNomeSobreNomeLogin(), usuario.getEmail()});
        } else {
            Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Não foi enviado e-mail ao usuário: {0} para: {1}", new Object[]{usuario.getNomeSobreNomeLogin(), usuario.getEmail()});
        }
    }

    @Override
    public Usuario buscarUsuarioId(Long id) {
        return manager.find(Usuario.class, id);
    }

    @Override
    public Usuario buscarUsuarioEmail(String email) {
        Query q = manager.createNamedQuery("UsuarioBean.buscarUsuarioEmail");
        q.setParameter("email", email);
        Usuario toReturn = null;
        try {
            toReturn = (Usuario) q.getSingleResult();
        } catch (NoResultException e) {
            //Não precisa de tratmento...
        }
        return toReturn;
    }

    @Override
    public Usuario buscarUsuarioLogin(String login) {
        Query q = manager.createNamedQuery("UsuarioBean.buscarUsuarioLogin");
        q.setParameter("login", login);
        Usuario toReturn = null;
        try {
            toReturn = (Usuario) q.getSingleResult();
        } catch (NoResultException e) {
            //Não precisa de tratmento...
        }
        return toReturn;
    }

    /**
     * Retorna todos os usuarios, se o usuário passado for administrador
     * Retorna todos os usuários com o papel abaixo do usuário passado, se o usuário passado
     * não for um administrador.
     * @param usuario
     * @return
     */
    @Override
    public Set<Usuario> buscarUsuariosAbaixoPapel(Usuario usuario) {
        if (rolesBean.getMaxRole(usuario.getRoles()).equals(Papeis.ADMINISTRADOR)) {
            return buscarTodosUsuarios();
        } else {
            TreeSet<Usuario> toReturn = new TreeSet<Usuario>();
            Set<Usuario> listUserAux = new TreeSet<Usuario>();
            for (Papeis papel : Papeis.values()) {
                if (papel.getLevel() <= usuario.getMaxRole().getPapel().getLevel()) {
                    listUserAux.addAll(buscarUsuariosPapel(papel));
                }
            }
            for (Usuario userToReturn : listUserAux) {
                if (userToReturn.getMaxRole().getPapel().getLevel() < usuario.getMaxRole().getPapel().getLevel()) {
                    toReturn.add(userToReturn);
                }
            }
            return toReturn;
        }
    }

    /**
     * Retorna todos os usuários que estão dentro do papel passado,
     * quanto mais baixo for o papel maior a qantidade de usuários.
     * Nesta aplicação um papel de maior hierarquia é considerado
     * como de menor hierarquia também, ou seja:
     * Um professor é um aluno, um coordenador é um professor...
     * Se você passar um aluno como parámetro serão retornados
     * todos os alunos, professores, coordenadores...
     * @param papeis
     * @return Um set com todos os usuários correspondentes ou um set vazio se não encontrar.
     */
    @Override
    public Set<Usuario> buscarUsuariosPapel(Papeis papel) {
        TreeSet<Usuario> toReturn = new TreeSet<Usuario>();
        Query q = manager.createNamedQuery("UsuarioBean.buscarUsuariosPapel");
        q.setParameter("papel", papel);
        toReturn.addAll(q.getResultList());
        return toReturn;
    }

    /**
     * Retorna somente usuário que possuem a MaxRole com papel 
     * igual a role passada.
     * @param papel
     * @return 
     */
    @Override
    public Set<Usuario> buscarUsuariosLimitadoAoPapel(Papeis papel) {
        Set<Usuario> total = buscarUsuariosPapel(papel);
        Set<Usuario> toReturn = new TreeSet<Usuario>();
        for(Usuario us : total){
            if(us.getMaxRole().getPapel().equals(papel)){
                us.getCertificacoesProfessorAcesso().size();
                toReturn.add(us);
            }
        }
        return toReturn;
    }

    /**
     * Enquanto não houver necessidade global, será privado.
     * @return
     */
    private Set<Usuario> buscarTodosUsuarios() {
        Query q = manager.createNamedQuery("UsuarioBean.buscarTodosUsuarios");
        return new TreeSet<Usuario>(q.getResultList());
    }

    /**
     * Passe a senha que deseja criptografar e os papeis que o usuário,
     * dono da senha passada, possui.
     * @param senha
     * @param roles
     * @return A senha criptografada.
     */
    @Override
    public String criptografarSenha(String senha, Set<Roles> roles) {
        return Criptografia.encodePassword(senha, roles);
    }

    private String geraSenha() {
        Random r = new Random();
        String[] a = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"};
        String[] b = {"!", "#", "@", "&", "$"};
        String[] c = {"A", "a", "B", "b", "C", "c", "D", "d", "E", "e", "F", "f", "G", "g", "H", "h", "I", "i", "J", "j", "K", "k", "L", "l", "Z", "z"};
        String[] d = {"K", "k", "L", "l", "M", "m", "N", "n", "O", "o", "P", "p", "Q", "q", "R", "r", "S", "s", "T", "t", "U", "u", "V", "v", "X", "x", "Z", "z"};
        int A = r.nextInt(a.length);
        int A2 = r.nextInt(a.length);
        int B = r.nextInt(b.length);
        int C = r.nextInt(c.length);
        int C2 = r.nextInt(c.length);
        int D = r.nextInt(d.length);
        int D2 = r.nextInt(d.length);
        String senha = "";
        senha += c[C];
        senha += d[D];
        senha += a[A2];
        senha += c[C2];
        senha += b[B];
        senha += d[D2];
        senha += a[A];
        return senha;
    }

    private void avisaSenhaEmail(String newPass, String url, Usuario usuario) {
        String body = this.bodyEmail(newPass, url, usuario);
        SimpleEmail simple = new SimpleEmail();
        simple.setBody(body);
        simple.setEmail(usuario.getEmail());
        simple.setSubject("Saber :: Controle de Acesso");
        this.emailSendBean.enviarEmailJMS(simple);
    }

    private String bodyEmail(String pass, String url, Usuario user) {
        String toReturn = "";
        String quebra = "<br>";
        toReturn += "<h3>Bem vindo ao Saber Certificação!</h3>";
        toReturn += "Seu login é: ";
        toReturn += "<strong>" + user.getLogin() + "</strong>";
        toReturn += quebra;
        toReturn += "Sua senha é: ";
        toReturn += "<strong>" + pass + "</strong>";
        toReturn += quebra;
        toReturn += "Você pode alterar sua senha dentro do Saber, após o 1º login!";
        toReturn += quebra;
        toReturn += "Dúvidas: gbvbahia01@gmail.com";
        toReturn += quebra;
        toReturn += url;
        return toReturn;
    }

    /**
     * Insere as Roles que são abaixo de sua maior role
     * Garante que um maior sempre será um menor.
     * @param usuario
     * @return
     */
    private Usuario verificaRoles(Usuario usuario) {
        if (usuario.getRoles().isEmpty()) {
            return usuario;
        }
        Papeis maxpapel = this.rolesBean.getMaxRole(usuario.getRoles());
        for (Roles role : rolesBean.getAllRoles()) {
            if (role.getPapel().getLevel() < maxpapel.getLevel()) {
                usuario.getRoles().add(role);
            }
        }
        return usuario;
    }

    /**
     * Incrementa o acesso do usuário não altera outras propriedades,
     * não utilize para atualizar outras informações.
     * @param usuario 
     */
    @Override
    public void incrementarAcesso(Usuario usuario) {
        usuario = this.manager.find(Usuario.class, usuario.getId());
        if (usuario != null) {
            usuario.setAcessos(usuario.getAcessos() + 1);
            this.manager.merge(usuario);
            this.manager.flush();
        }
    }
}
